How to write demos that work ============================ (or How to bash the metal and get away with it) by Comrade J, Share and Enjoy (retired) Are you fed up of downloading a new demo, running it and finding your Amiga power light sitting there flashing at you? Are you tired of the contents of your chipram flashing through the bitplane registers in a rather random fashion when you run 'Duffex's Megademo'? Do you want demos that actually run? Because I do. I'm fed up completely with all these rubbish coders who can't do their job properly... Now, since those long days and nights bashing away at Share and Enjoy demos I've been involved in all sorts of Amiga programming, involving new AGA machines, CD, 16-bit audio and all sorts of other wonderful things that I can't talk about, both via the OS and at a hardware level. Most demos I've seen use similar startup code to that I was using back in 1988. Hey guys, wake up! The Amiga has changed quite a bit since then. So. Here are some tips on what to do and what not to do: 1. RTFM. ======== Read the F**king manuals. All of them. Borrow them off friends or from your local public library if you have to. Make sure you follow the hardware rules to the letter. If it says "Leave this bit cleared" then don't set it! There is a lot of useful informatiton in the 'boring' OS Rom Kernal Manuals that you may be suprised to know. Read the "General Amiga Development Guidelines" in the new (grey) Hardware Reference Manual and follow them TO THE LETTER. Don't use self-modifying code. A common bit of code I see is: ... in the setup code move.l $6c.w,old ... at the end of the interrupt movem.l (sp)+,a0-a6/d0-d7 dc.w $4ef9 ; jmp instruction old dc.l 0 ; self modifying!!!! DONT DO THIS! This is much better (although it still hits $6c which is not a good thing - It's much better to use AddIntServer() to call your interrupts, but more on that next time....) ... in the setup code move.l $6c.w,old ... at the end of the interrupt movem.l (sp)+,a0-a6/d0-d7 move.l old,-(sp) ; push old address to stack rts ... in your data section old dc.l 0 68020 and above processors with cache enabled often barf at the first piece of code (the cache still contains the JMP 0 instruction which isn't then altered), but the second piece works fine on the '040. 2. Proper Copper startup. ========================= IF you are going to use the copper then this is how you should set it up. The current workbench view and copper address are stored, the system frozen, and then the copper enabled. On exit the workbench view is restored. This guarantees your demo will run on an AGA (Amiga 1200) machine, even if set into some weird screenmode before running your code. Otherwise under AGA, the hardware registers can be in some strange states before your code runs, beware! The LoadView(NULL) forces the display to a standard, empty position, flushing the crap out of the hardware registers: Note. There is a bug in the V39 OS on Amiga 1200/4000 and the sprite resolution is *not* reset, you will have to do this manually if you use sprites... Two WaitTOF() calls are needed after the LoadView to wait for both the long and short frame copperlists of interlaced displays to finish. I'm writing this code off the top of my head, if you spot any obvious bugs email me at the address below, or leave mail to me on Bad Dreams BBS. include "exec/macros.i" include "exec/funcdef.i" ; keep code simple and include "exec/exec_lib.i" ; easy to read - use include "graphics/gfxbase.i" ; the includes! include "graphics/gfx_lib.i" include "misc/easystart.i" ; Allows startup from ; icon section mycode,code ; need not be in chipram StartCopper: move.l 4.w,a6 ; get ExecBase lea gfxname,a1 ; graphics name moveq #0,d0 ; any version jsr _LVOOpenLibrary(a6) tst.l d0 beq End ; failed to open? Then quit move.l d0,gfxbase move.l d0,a6 move.l gb_ActiView(a6),wbview ; store current view address ; gb_ActiView = 32 move.l gb_LOFlist(a6),wbcop ; store current wb copper ; gb_LOFlist = 48 move.w #0,a1 ; clears full long-word jsr _LVOLoadView(a6) ; Flush View to nothing jsr _LVOWaitTOF(a6) ; Wait once jsr _LVOWaitTOF(a6) ; Wait again. ; Now you can hit the copper! move.l 4.w,a6 jsr _LVOForbid(a6) ; Suspend multitasking! move.l mycopper,$dff080 ; bang it straight in. ; (DO NOT F**K WITH GFXBASE!) *** DO YOUR FUNKY STUFF HERE *** CloseDown: move.l 4.w,a6 jsr _LVOPermit(a6) ; Enable multitasking move.l wbview,a1 move.l gfxbase,a6 jsr _LVOLoadView(a6) ; Fix view move.l wbcop,$dff080 ; Kick it into life move.l a6,a1 move.l 4.w,a6 jsr _LVOCloseLibrary(a6) ; EVERYONE FORGETS THIS!!!! End: rts section mydata,data_C ; keep data & code seperate! copperlist dc.w $180,0 ; background black dc.w $5c07,$fffe ; wait for $5c07,$fffe dc.w $180,$ff0 ; background yellow dc.w $ffff,$fffe dc.w $ffff,$fffe ; Copper end (always do two ; copper end cmds!) wbview dc.l 0 wbcop dc.l 0 gfxbase dc.l 0 gfxname dc.b "graphics.library",0 3. Your code won't run from an icon. ==================================== You stick an icon for your new demo (not everyone uses the CLI!) and it either crashes or doesn't give back all the RAM it uses. Why? Icon startup needs specific code to reply to the workbench message. With the excellent Hisoft Devpac assember, all you need to do is add the line include "misc/easystart.i" and it magically works! For those without Devpac, here is the relevent code: --------------------------------------------------------- * some startup code to make a Workbench execute look like the CLI * based loosely on RKM Vol 1 page 4-36 * Include this at the front of your program * after any other includes * note that this needs exec/exec_lib.i IFND EXEC_EXEC_I include "exec/exec.i" ENDC IFND LIBRARIES_DOSEXTENS_I include "libraries/dosextens.i ENDC movem.l d0/a0,-(sp) save initial values clr.l returnMsg sub.l a1,a1 move.l 4.w,a6 jsr _LVOFindTask(a6) find us move.l d0,a4 tst.l pr_CLI(a4) beq.s fromWorkbench * we were called from the CLI movem.l (sp)+,d0/a0 restore regs bra end_startup and run the user prog * we were called from the Workbench fromWorkbench lea pr_MsgPort(a4),a0 move.l 4.w,a6 jsr _LVOWaitPort(A6) wait for a message lea pr_MsgPort(a4),a0 jsr _LVOGetMsg(A6) then get it move.l d0,returnMsg save it for later reply * do some other stuff here RSN like the command line etc nop movem.l (sp)+,d0/a0 restore end_startup bsr.s _main call our program * returns to here with exit code in d0 move.l d0,-(sp) save it tst.l returnMsg beq.s exitToDOS if I was a CLI move.l 4.w,a6 jsr _LVOForbid(a6) move.l returnMsg(pc),a1 jsr _LVOPermit(a6) exitToDOS move.l (sp)+,d0 exit code rts * startup code variable returnMsg dc.l 0 * the program starts here even _main --------------------------------------------------------- 4. How do I tell if I'm running on an Amiga 1200/4000? ====================================================== Do *NOT* check library revision numbers, V39 OS can and does run on standard & ECS chipset machines (This Amiga 3000 is currently running V39). This code will check for AGA move.w $dff07c,d0 and.w #$ff,d0 cmp.w #$f8,d0 bne.s .notaga ; Do your funky AGA Stuff in here! .notaga 5. Use Relocatable Code ======================= If you write demos that run from a fixed address you should be shot. NEVER EVER DO THIS. It's stupid and completely unnecessary. If you require bitplanes to be on a 64Kb boundary then try the following (in pseudo-code because I'm too lazy to write it in asm for you): for c=0 to (top of chip ram) step 65536 if AllocAbs(c,NUMBER_OF_BYTES_YOU_WANT) == TRUE then goto ok: next c: print "sorry. No free ram. Close down something and retry demo!" stop ok: Run_Outrageous_demo with mem at c Keep your code in multiple sections. Several small sections are better than one large section, they will more easilly fit in and run on a system with fragmented memory. 6. Don't Crunch demos! ====================== Don't ever use Tetrapack or Bytekiller based packers. They are crap. Many more demos fall over due to being packed with crap packers than anything else. If you are spreading your demo by electronic means (which most people do now, the days of the SAE Demodisks are long gone!) then assemble your code, and use LHARC to archive it, you will get better compression with LHARC than with most runtime packers. If you *have* to pack your demos, then use Powerpacker 4+, Turbo Imploder or Titanics Cruncher, which I've had no problems with myself. 7. Don't use the K-Seka assembler! ================================== It's dead and buried. Get a life, get a real assembler. Hisoft Devpac is probably the best all-round assembler, although I use ArgAsm which is astonishingly fast. 8. Don't use the hardware unless you have to! ============================================= This one is aimed particularly at utility authors. I've seen some *awfully* written utilities, for example (although I don't want to single them out as there are plenty of others) the Kefrens IFF converter. There is NO REASON why this has to have it's own copperlist. A standard OS-friendly version opening it's own screen works perfectly (I still use the original SCA IFF-Converter), and multitasks properly. 9. Beware bogus input falling through to Workbench ================================================== If you keep multitasking enabled and run your own copperlist remember that any input (mouse clicks, key presses, etc) fall through to the workbench. The correct way to get around this is to add an input server to the IDCMP food chain (see - you *do* have to read the other manuals!) at a high priority to grab all input events before workbench/cli can get to them. Look at the sourcecode for Protracker for an excellent example of how to do the job properly. Well done Lars! 10. Have fun! ============= Too many people out there (particularly the American OS-Lamic Fundamentalists) try to tell us that you should never program at a hardware level. If you're programming for fun, ignore them! But try and put a little thought into how your code will work on other machines, nothing annoys people more than downloading 400Kb of demo and then finding it blows up on their machines. I'm not naming any names, but there are quite a few groups who I have no intention of downloading their demos again because I know it's a waste of download. With the launch of the Amiga 1200 you cannot just write for 1.3 Amiga 500's any more. Let's go out there and write some shit hot demos! -------------------------------------------------------------------- This text is Copyright (C) 1992 Share and Enjoy, but may be freely distributed in any electronic form. All opinions expressed in this article are my own, and in no way reflect those of Share and Enjoy or any BBS this file may be found on. I didn't write this for fun, I wrote it for you to use! If you strongly disagree with anything I write, or you want to send me some source or demos to test on Amiga 1200/4000 etc, or you have questions about Amiga programming, or suggestions for future articles, or just want to chat about the best way to optimise automatic copperlist generation code, then contact me via email at: comradej@althera.demon.co.uk or by email at Bad Dreams BBS.